const storage = (function () {
  const msEnum = { month: 2592e6, day: 864e5, hour: 36e5, minute: 6e4 };
  const EXPIRES_STORE_KEY = '__storage_expires_';

  function getExpiresOption(option) {
    /*
     * expires：过期时间（为无效值时不过期），类型 Number；
     * unit：过期时间的单位，默认是 day, 可选: month,day,hour,minute
     * */
    let time;
    let opt = { expires: 1, unit: 'day' };
    let { expires, unit } = Object.assign(opt, option);
    if (Number.isFinite(expires) && expires > 0) {
      time = Date.now() + expires * (msEnum[unit] || msEnum.day);
    } else {
      time = Infinity;
    }
    return { unit, time };
  }
  function encodeJson(data) {
    try {
      return JSON.stringify(data === 0 || !!data ? data : '');
    } catch (e) {
      return '';
    }
  }
  function decodeJson(data, defaultValue) {
    if (typeof defaultValue === 'undefined') {
      defaultValue = data;
    }
    try {
      return typeof data === 'string' && data ? JSON.parse(data) : defaultValue;
    } catch (e) {
      return defaultValue;
    }
  }
  function setExpires(key, option) {
    const store = decodeJson(window.localStorage.getItem(EXPIRES_STORE_KEY), {});
    store[key] = getExpiresOption(option);
    window.localStorage.setItem(EXPIRES_STORE_KEY, encodeJson(store));
  }
  function getExpires(key) {
    const store = decodeJson(window.localStorage.getItem(EXPIRES_STORE_KEY), {});
    const { time, unit } = Object.assign({}, store[key]);
    const hasOption = Number.isFinite(time) && time > 0 && msEnum[unit];
    return hasOption ? time < Date.now() : false;
  }

  class StorageApi {
    constructor(storage, useExpires) {
      this.storage = storage;
      this.useExpires = useExpires === true;
    }
    setItem(key, value, option) {
      if (this.useExpires) {
        setExpires(key, option);
      }
      this.storage.setItem(key, encodeJson(value));
    }
    getItem(key, defaultValue) {
      let value = decodeJson(this.storage.getItem(key), defaultValue);
      let isExpires = this.useExpires ? getExpires(key) : false;
      if (isExpires) {
        this.storage.removeItem(key);
        value = defaultValue;
      }
      return typeof value !== 'undefined' && value !== null ? value : defaultValue;
    }
    removeItem(key) {
      this.storage.removeItem(key);
    }
    clear() {
      this.storage.clear();
    }
  }

  const local = new StorageApi(window.localStorage, true);
  const session = new StorageApi(window.sessionStorage);
  const clear = function () {
    storage.session.clear();
    storage.local.clear();
  };

  return { local, session, clear };
})();

export default storage;
